package me.leon.ext.android

import android.Manifest.permission
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import androidx.core.content.FileProvider
import java.io.File
import java.util.*
import me.leon.ext.Utils.app
import me.leon.ext.java.toFile

/**
 * <pre> author: Blankj blog : http://blankj.com time : 2016/09/23 desc : utils about intent </pre>
 * *
 */
object IntentUtils {

    /**
     * Return whether the intent is available.
     *
     * @param intent The intent.
     * @return `true`: yes<br></br>`false`: no
     */
    fun isIntentAvailable(intent: Intent) =
        app.packageManager
            .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
            .isNotEmpty()

    /**
     * Return the intent of uninstall app.
     *
     * @param packageName The name of the package.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of uninstall app
     */
    @JvmOverloads
    fun getUninstallAppIntent(packageName: String, isNewTask: Boolean = false): Intent {
        val intent = Intent(Intent.ACTION_DELETE)
        intent.data = Uri.parse("package:$packageName")
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of launch app.
     *
     * @param packageName The name of the package.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of launch app
     */
    @JvmOverloads
    fun getLaunchAppIntent(packageName: String?, isNewTask: Boolean = false): Intent? {
        val intent = app.packageManager.getLaunchIntentForPackage(packageName!!) ?: return null
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of launch app details settings.
     *
     * @param packageName The name of the package.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of launch app details settings
     */
    @JvmOverloads
    fun getLaunchAppDetailsSettingsIntent(packageName: String, isNewTask: Boolean = false): Intent {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
        intent.data = Uri.parse("package:$packageName")
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of share text.
     *
     * @param content The content.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share text
     */
    @JvmOverloads
    fun getShareTextIntent(content: String?, isNewTask: Boolean = false): Intent {
        val intent = Intent(Intent.ACTION_SEND)
        intent.type = "text/plain"
        intent.putExtra(Intent.EXTRA_TEXT, content)
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of share image.
     *
     * @param content The content.
     * @param imagePath The path of image.
     * @return the intent of share image
     */
    fun getShareImageIntent(content: String?, imagePath: String?): Intent? {
        return getShareImageIntent(content, imagePath, false)
    }

    /**
     * Return the intent of share image.
     *
     * @param content The content.
     * @param imagePath The path of image.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share image
     */
    fun getShareImageIntent(content: String?, imagePath: String?, isNewTask: Boolean) =
        if (imagePath.isNullOrEmpty()) null
        else getShareImageIntent(content, File(imagePath), isNewTask)

    /**
     * Return the intent of share image.
     *
     * @param content The content.
     * @param image The file of image.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share image
     */
    @JvmOverloads
    fun getShareImageIntent(content: String?, image: File?, isNewTask: Boolean = false) =
        if (image == null || !image.isFile) null
        else getShareImageIntent(content, file2Uri(image), isNewTask)

    /**
     * Return the intent of share image.
     *
     * @param content The content.
     * @param uri The uri of image.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share image
     */
    @JvmOverloads
    fun getShareImageIntent(content: String?, uri: Uri?, isNewTask: Boolean = false): Intent {
        val intent = Intent(Intent.ACTION_SEND)
        intent.putExtra(Intent.EXTRA_TEXT, content)
        intent.putExtra(Intent.EXTRA_STREAM, uri)
        intent.type = "image/*"
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of share images.
     *
     * @param content The content.
     * @param imagePaths The paths of images.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share images
     */
    @JvmOverloads
    fun getShareImageIntent(
        content: String?,
        imagePaths: LinkedList<String>?,
        isNewTask: Boolean = false
    ): Intent? {

        if (imagePaths.isNullOrEmpty()) return null
        val files: MutableList<File> = ArrayList()
        for (imagePath in imagePaths) {
            files.add(File(imagePath))
        }
        return getShareImageIntent(content, files, isNewTask)
    }

    /**
     * Return the intent of share images.
     *
     * @param content The content.
     * @param images The files of images.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share images
     */
    @JvmOverloads
    fun getShareImageIntent(
        content: String?,
        images: List<File>?,
        isNewTask: Boolean = false
    ): Intent? {
        if (images.isNullOrEmpty()) return null
        val uris = ArrayList<Uri?>()
        for (image in images) {
            if (!image.isFile) continue
            uris.add(file2Uri(image))
        }
        return getShareImageIntent(content, uris, isNewTask)
    }

    /**
     * Return the intent of share images.
     *
     * @param content The content.
     * @param uris The uris of image.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of share image
     */
    @JvmOverloads
    fun getShareImageIntent(
        content: String?,
        uris: ArrayList<Uri?>?,
        isNewTask: Boolean = false
    ): Intent {
        val intent = Intent(Intent.ACTION_SEND_MULTIPLE)
        intent.putExtra(Intent.EXTRA_TEXT, content)
        intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
        intent.type = "image/*"
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of component.
     *
     * @param packageName The name of the package.
     * @param className The name of class.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of component
     */
    fun getComponentIntent(packageName: String, className: String, isNewTask: Boolean) =
        getComponentIntent(packageName, className, null, isNewTask)

    /**
     * Return the intent of component.
     *
     * @param packageName The name of the package.
     * @param className The name of class.
     * @param bundle The Bundle of extras to add to this intent.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of component
     */
    @JvmOverloads
    fun getComponentIntent(
        packageName: String,
        className: String,
        bundle: Bundle? = null,
        isNewTask: Boolean = false
    ): Intent {
        val intent = Intent(Intent.ACTION_VIEW)
        if (bundle != null) intent.putExtras(bundle)
        val cn = ComponentName(packageName, className)
        intent.component = cn
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of shutdown.
     *
     * Requires root permission or hold `android:sharedUserId="android.uid.system"`,
     * `<uses-permission android:name="android.permission.SHUTDOWN" />` in manifest.
     *
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of shutdown
     */
    @JvmOverloads
    fun getShutdownIntent(isNewTask: Boolean = false) =
        getIntent(
            Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN").apply {
                putExtra("android.intent.extra.KEY_CONFIRM", false)
            },
            isNewTask
        )

    /**
     * Return the intent of dial.
     *
     * @param phoneNumber The phone number.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of dial
     */
    @JvmOverloads
    fun getDialIntent(phoneNumber: String, isNewTask: Boolean = false) =
        getIntent(Intent(Intent.ACTION_DIAL, Uri.parse("tel:$phoneNumber")), isNewTask)

    /**
     * Return the intent of call.
     *
     * Must hold `<uses-permission android:name="android.permission.CALL_PHONE" />`
     *
     * @param phoneNumber The phone number.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of call
     */
    @JvmOverloads
    @RequiresPermission(permission.CALL_PHONE)
    fun getCallIntent(phoneNumber: String, isNewTask: Boolean = false) =
        getIntent(Intent("android.intent.action.CALL", Uri.parse("tel:$phoneNumber")), isNewTask)

    /**
     * Return the intent of send SMS.
     *
     * @param phoneNumber The phone number.
     * @param content The content of SMS.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of send SMS
     */
    @JvmOverloads
    fun getSendSmsIntent(
        phoneNumber: String,
        content: String?,
        isNewTask: Boolean = false
    ): Intent {
        val uri = Uri.parse("smsto:$phoneNumber")
        val intent = Intent(Intent.ACTION_SENDTO, uri)
        intent.putExtra("sms_body", content)
        return getIntent(intent, isNewTask)
    }

    /**
     * Return the intent of capture.
     *
     * @param outUri The uri of output.
     * @param isNewTask True to add flag of new task, false otherwise.
     * @return the intent of capture
     */
    @JvmOverloads
    fun getCaptureIntent(outUri: Uri?, isNewTask: Boolean = false): Intent {
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outUri)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        return getIntent(intent, isNewTask)
    }

    private fun getIntent(intent: Intent, isNewTask: Boolean): Intent {
        return if (isNewTask) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) else intent
    }

    ///////////////////////////////////////////////////////////////////////////
    // other utils methods
    ///////////////////////////////////////////////////////////////////////////

    private fun file2Uri(file: File?): Uri? {
        if (file == null) return null
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val authority = app.packageName + ".utilcode.provider"
            FileProvider.getUriForFile(app, authority, file)
        } else {
            Uri.fromFile(file)
        }
    }

    /**
     * Notify system to scan the file.
     *
     * @param file The file.
     */
    fun notifySystemToScan(file: File?) {
        if (file == null || !file.exists()) return
        val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
        val uri = file2Uri(file)
        intent.data = uri
        app.sendBroadcast(intent)
    }

    /**
     * Notify system to scan the file.
     *
     * @param filePath The path of file.
     */
    fun notifySystemToScan(filePath: String) {
        notifySystemToScan(filePath.toFile())
    }

    fun hasInstallUnknownPermission() =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            app.packageManager.canRequestPackageInstalls()
        else true

    /**
     *
     * 安装未知应用权限 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun goUnknownPermissionSettings() {
        app.startActivity(
            Intent(
                    Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
                    Uri.parse("package:${app.packageName}")
                )
                .apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
        )
    }
}
